Spring Boot 如何实现Bean的刷新 | 您所在的位置:网站首页 › spring bean的加载 › Spring Boot 如何实现Bean的刷新 |
![]() 首先得了解Scope(作用域),简单介绍两种。 1. singleton 单例类型 整个程序运行期间,Spring容器只会有一个对应类的Bean实例,不管被加载到哪里使用,都是一个实例对象。 曾经,我犯过一个错。将公用返回对象以默认的方式加载至Spring容器(笑) 2. prototype 原型类型 和单例相反,这种加载模式,Bean实例不管在哪里被获取,都不是同一个对象。 刚好可以解决上面,公用返回对象的问题(笑)(笑) 2. 如何实现 —— 建立自己的作用域毕竟面向浏览器编程的我,也不是白吹的。 浏览器启动 -> spring bean 自定义作用域 -> 点击 -> 浏览 -> 原来如此 -> 点赞 -> 再见 等等,我看的啥来着? // 注册一个名叫 “refresh” 的bean作用域,处理对象是 RefreshScope的实例 applicationContext.getBeanFactory().registerScope("refresh", refreshScope);RefreshScope类需要实现Scope接口 (1)get(String name, ObjectFactory objectFactory)方法 通过名字,获取bean的实例对象。 关于第二参数:objectFactory,大致意思就是目标类构造工厂 OK了。 3. 如何实现 —— 使用refresh作用域 // 创建Refresh注解 @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Scope("refresh") @Documented public @interface Refresh { ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS; }我们需要Bean配置变化的时候进行刷新。 所以应该让Spring把Bean的获取操作交由我们自己处理(上面的get方法)。 再利用原型加载prototype类似的机制,让Bean每次都调用get方法。 @Bean @Refresh public A a(){ return new A(); }可以试着在@Autowired加载A实例的地方,打个断点,看看A对象的类型。 加载的A实例并不是A实例本身,通过添加@Refresh注解后,ScopedProxyMode.TARGET_CLASS参数(使用CGLIB代理),让A的注入方式变为代理注入。 注入的是一个代理对象,实现懒加载,在需要调用的时候,进行对象获取(就是上述的get方法) 4. 如何实现 —— 回到我们的作用域 RefreshScope类 public class RefreshScope implements Scope { // 省略*** @Override public Object get(String name, ObjectFactory objectFactory) { //TODO } // 省略*** }现在每次使用添加l @Refresh注解的Bean时,都会调用get方法。 如同原型加载一样,每次都生成新的对象不就成功刷新了嘛? public class RefreshScope implements Scope { // 省略*** @Override public Object get(String name, ObjectFactory objectFactory) { return objectFactory.getObject(); } // 省略*** }显然是可以的,每次都会再去执行一遍a()方法。就可以在这里获取最新配置,然后重新生成A实例。 @Bean @Refresh public A a(){ return new A(); }NO!!!!!! 缓存是个好东西呀,没有发生变化的时候,重新生成新对象,不是很浪费嘛。 public class RefreshScope implements Scope { // 省略*** // get方法过来的name有前缀 private static final String TARGET = "scopedTarget."; // 自己定义的一个缓存类,可以自己选择存取方式进行实现,需要考虑线程安全问题 private BeanCache beanCache = new BeanCache(); @Override public Object get(String name, ObjectFactory objectFactory) { Object bean = beanCache.get(name); // 加个缓存判断 return bean==null?beanCache.put(name, objectFactory.getObject()):bean; } // 自定义一个缓存失效方法 public void refresh()(String name) { beanCache.remove(TARGET + name); } // 省略*** } 5. 完成要进行Bean刷新,调用RefreshScope的refresh()方法就行了。 比如MongoTemplate对象。 @Bean @Refresh public MongoTemplate mongoTemplate() { return new MongoTemplate(new MongoClient(MongoConfig.getHost(), MongoConfig.getPort()), MongoConfig.getDbName()); }当MongoConfig对象参数发生变化。 //使缓存失效。 refreshScope.refresh('mongoTemplate')关于refreshScope实例,可以交给Spring容器管理,也可以自己管理。 当缓存失效后,使用到mongoTemplate时,将会再次调用mongoTemplate()方法重新生成,并缓存MongoTemplate实例。 6. 后记无 |
CopyRight 2018-2019 实验室设备网 版权所有 |